package com.run_java_test.test_run;

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;

@Component
public class DynamicClassManager {

    private static final String BASE_PATH = "D:\\a2software_cache\\IDEAProject\\self\\java_study_springboot_run_java_source_code\\dynamic_sources";

    @Autowired
    private GenericApplicationContext applicationContext;

    @Autowired
    private RequestMappingHandlerMapping handlerMapping;

    /**
     * 保存上传的源码文件
     */
    public void saveSourceFile(String fileName, String sourceCode) throws IOException {
        File file = new File(BASE_PATH + fileName);
        file.getParentFile().mkdirs();
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(sourceCode);
        }
    }

    /**
     * 编译源码文件
     */
    private void compileSourceFiles() throws IOException {
        File sourceDir = new File(BASE_PATH);
        File[] javaFiles = sourceDir.listFiles((dir, name) -> name.endsWith(".java"));

        if (javaFiles != null && javaFiles.length > 0) {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

            Iterable<? extends javax.tools.JavaFileObject> compilationUnits =
                    fileManager.getJavaFileObjects(javaFiles);
            compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();

            fileManager.close();
        }
    }

    /**
     * 加载编译生成的类
     */
    private void loadCompiledClasses() throws Exception {
        File classDir = new File(BASE_PATH);
        URL[] urls = {classDir.toURI().toURL()};
        URLClassLoader classLoader = new URLClassLoader(urls);

        File[] classFiles = classDir.listFiles((dir, name) -> name.endsWith(".class"));
        if (classFiles != null) {
            for (File file : classFiles) {
                String className = file.getName().replace(".class", "");
                Class<?> clazz = classLoader.loadClass(className);
                registerControllerBean(clazz);
            }
        }
    }

    /**
     * 动态注册 Controller Bean
     */
    private <T> void registerControllerBean(Class<T> clazz) {
        T controllerInstance;
        try {
            controllerInstance = clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("无法实例化动态 Controller 类", e);
        }

        applicationContext.registerBean(clazz.getSimpleName(), clazz, () -> controllerInstance);
        try {
            handlerMapping.afterPropertiesSet();
        } catch (Exception e) {
            throw new RuntimeException("刷新 HandlerMapping 时出错", e);
        }
    }

    /**
     * 项目启动时重新加载动态类
     */
    @PostConstruct
    public void reloadDynamicClasses() {
        try {
            compileSourceFiles();
            loadCompiledClasses();
        } catch (Exception e) {
            throw new RuntimeException("加载动态类失败", e);
        }
    }

    /**
     * 示例：上传源码并注册
     */
    public void uploadAndRegister(String fileName, String sourceCode) throws Exception {
        saveSourceFile(fileName, sourceCode);
        compileSourceFiles();
        loadCompiledClasses();
    }
}
